package com.huaxindata.im.service;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.os.Vibrator;
import android.support.annotation.Nullable;

import com.huaxin.common.event.HxIsBackgroundProcessesEvent;
import com.huaxindata.im.constants.mqtt.MqttConstants;
import com.huaxindata.im.main.chat.Helper.ContactHelper;
import com.huaxindata.im.main.chat.Helper.FileHelper;
import com.huaxindata.im.main.chat.Helper.MessageHelper;
import com.huaxindata.im.main.manager.ContactManager;
import com.huaxindata.im.model.db.MessageStore;
import com.huaxindata.im.model.entity.ChatMessage;
import com.huaxindata.im.model.entity.ChatMessageBody;
import com.huaxindata.im.model.entity.ChatSysMessageBody;
import com.huaxindata.im.model.utils.ReceivePlayload;
import com.huaxindata.im.model.utils.SendPlayload;
import com.huaxindata.im.util.Log;
import com.huaxindata.im.util.SharePreferenceUtil;
import com.huaxindata.im.util.TelPhoneUtil;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2017/8/16.
 * 一个在后台接收消息的服务类，接收消息过程如下
 * 1、连接服务器，包括先初始化MqttAndroidClient对象
 * 2、订阅指定主题
 * 3、发布消息
 * 4、取消订阅
 * 5、断开连接
 */

public class MessageService extends Service implements MessageHelper.OnServiceCallback {

    private static final String TAG = "MessageService";

    private MqttAndroidClient      mMqttClient;
    private String                 clientId;
    private ConnectionLostListener mConnectionLostListener;

    private List<OnMessageReceiveListener> mReceiveListeners = new ArrayList<>();

    public void addMessageReceiveListener(OnMessageReceiveListener listener) {
        mReceiveListeners.add(listener);
    }

    public void removeMessageReceiveListener(OnMessageReceiveListener listener) {
        mReceiveListeners.remove(listener);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        MessageHelper.setServiceCallback(this);
        EventBus.getDefault().register(this);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    private final MyBinder mBinder = new MyBinder();

    /**
     * 用于绑定服务，获取本服务对象
     */
    public class MyBinder extends Binder {
        public MessageService getService() {
            return MessageService.this;
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_NOT_STICKY;
    }

    @Override
    public void onMessageHelperCallback(String groupId, boolean isSubscribe) {
        if (isSubscribe) {
            subscribe(groupId);
        } else {
            unSubscribe(groupId);
        }
    }

    /**
     * 接收到的消息在此处作初步处理，这里接收到的消息线程是主线程
     * 接收到的消息在这里存入数据库
     *
     * @param chatMessage
     */
    public void onReceiveMessage(ChatMessage chatMessage) {
        if (chatMessage == null || clientId == null)
            return;
        if (!chatMessage.receiver.equals(clientId) && !ContactHelper.isGroup(chatMessage.receiver)) {
            return;//收信人既不是当前用户也不是用户所属的群组，说明这是错误的消息，不鸟他
        }
        chatMessage.read = 0;//置消息为未读
        chatMessage.messageState = ChatMessage.Status.DOING;

        MessageStore.insert(chatMessage);//存入数据库
        int type = chatMessage.type;
        if (type == ChatMessageBody.Type.SYSTEM) {
            String content = chatMessage.message;
            if (content != null) {//如果消息的内容主体为空，则不处理
                ChatSysMessageBody chatSysMessageBody = (ChatSysMessageBody) chatMessage.getMessageBody();
                // String[] msgBody = content.split(HxMessage.PREX);//消息体内容
                //  String action = msgBody[0];
                if (ChatSysMessageBody.SysMessageType.ACTION_ONLINE_NOTICE.equals(chatSysMessageBody.action)) {
                    String imei = chatSysMessageBody.getSystemMessageInfo()[1];
                    if ((clientId + "_" + TelPhoneUtil.getIMEI(this)).equals(imei)) {
                        Log.e(TAG, "xxx=====本机上线");
                    } else {
                        Log.e(TAG, "xxx======有人登录同一帐号，你被挤掉线了");
                        mConnectionLostListener.connectionLost();
                    }
                } else {
                    MessageHelper.handleSystemMessage(chatMessage);
                }
            }
        } else if (type == ChatMessageBody.Type.VOICE || type == ChatMessageBody.Type.IMAGE || type == ChatMessageBody.Type.FILE) {
            //不需要全部下载，可优化
            // 如果是收到的是语音，图片，文件等消息，则立即开始下载，下载成功存入数据库
            Log.e(TAG, "xxx==收到语音消息:" + chatMessage.message);
            FileHelper.downLoadFileMessage(chatMessage, this, null);
        }
        //消息回调
        performCallback(chatMessage);
        //通知用户
        notifyUsers(chatMessage);
        Log.e(TAG, "xxx==收到消息:" + chatMessage.message);
        receiverMessageBroadcast(chatMessage);
    }

    public boolean isBackground;

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void isBackgroundProcesses(HxIsBackgroundProcessesEvent message) {
        isBackground = message.isBackground;
    }

    /**
     * 只有在后台进程的时候，才发送消息广播
     */
    private void receiverMessageBroadcast(ChatMessage hxMessage) {
        if (hxMessage.sender.equals(hxMessage.receiver)) {//如果是自己发送的上线消息不通知
            return;
        }
        if (isBackground) {
            Intent intent = new Intent();
            intent.putExtra("RECEIVER_MESSAGE", hxMessage);
            intent.setAction("android.intent.action.RECEIVE_MEESAGE_BROADCAST");
            sendBroadcast(intent);
        }

    }

    /**
     * 通知用户消息来了
     */
    private void notifyUsers(ChatMessage chatMessage) {
        boolean isFriend = ContactManager.isFriend(chatMessage.sender);
        if (isFriend) {
            /**
             * 是否对该用户设置了免打扰
             */
            boolean isNotDisturb = SharePreferenceUtil.getBoolean(this, "friend_" + chatMessage.sender, false);
            if (isNotDisturb) {//设置了免打扰就不震动和发声音
                return;
            }
        } else if (ContactManager.isGroup(chatMessage.receiver)) {//是否是群消息
            boolean isNotDisturb = SharePreferenceUtil.getBoolean(this, "group_" + chatMessage.receiver, false);
            if (isNotDisturb) {//设置了免打扰就不震动和发声音
                return;
            }
        }
        if (chatMessage.sender.equals(chatMessage.receiver)) {//如果是自己发送的上线消息不通知
            return;
        }
        final MediaPlayer player = MessageHelper.getMediaPlayer(this);
        final Vibrator vibrator = MessageHelper.getVibrator(this);
        if (player != null) {
            if (player.isPlaying()) {
                player.seekTo(0);
            } else {
                player.start();
            }
        }
        if (vibrator != null) {
            long[] pattern = {200, 600, 200};
            vibrator.vibrate(pattern, -1);//振动
        }
    }

    /**
     * 执行回调，提示消息来了
     */
    private void performCallback(ChatMessage message) {
        for (OnMessageReceiveListener listener : mReceiveListeners) {
            listener.receiveMessage(message);
        }
    }

    /**
     * 连接服务器，连接成功后自动订阅
     *
     * @param clientId
     */
    public void connectAndSubscribe(String clientId, final String[] topics) {
        if (clientId == null) {
            Log.e(TAG, "xxx==connectAndSubscribe==客户端id为空，拒绝连接");
            return;
        }
        if (mMqttClient != null && mMqttClient.isConnected()) {
            Log.e(TAG, "xxx==connectAndSubscribe==已经在线，不用再连接了");
            return;
        }
        this.clientId = clientId;
        mMqttClient = new MqttAndroidClient(this, MqttConstants.MQTT_SERVER_URL, clientId);
        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setAutomaticReconnect(false);//设置自动重连
        mqttConnectOptions.setCleanSession(false);//是否清除session
        mqttConnectOptions.setUserName(MqttConstants.MQTT_USER_NAME + "_" + TelPhoneUtil.getIMEI(this));
        mqttConnectOptions.setPassword(MqttConstants.MQTT_PASSWORD.toCharArray());
        mqttConnectOptions.setConnectionTimeout(10);
        mqttConnectOptions.setKeepAliveInterval(20);
        mMqttClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {
                if (reconnect) {
                    //如果是自动重连的，且清除了session，则要重新订阅
                    Log.e(TAG, "xxx==connect==connectComplete==自动重连");
                } else {
                    Log.e(TAG, "xxx==connect==connectComplete==连接完成");
                    //执行订阅的方法
                    subscribe(topics);
                }
            }

            @Override
            public void connectionLost(Throwable cause) {
                Log.e(TAG, "xxx==connect==connectionLost==出现异常，连接丢失");
                //  ToastUtil.showToast(getApplicationContext(),"出现异常，连接丢失");
                //重新连接
                //  connectAndSubscribe(UserManager.getClientId(), ContactManager.getTopics());
                //                if (mConnectionLostListener != null) {
                //                    mConnectionLostListener.connectionLost();
                //                }
            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                //收到服务器推送过来的消息
                ChatMessage chatMessage = ReceivePlayload.parseMqttMessage(message);
                Log.e("lwjing", "ReceivePlayload解析后= " + chatMessage.toString());
                onReceiveMessage(chatMessage);
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
            }
        });
        connect(mqttConnectOptions);
    }

    public void connect(MqttConnectOptions mqttConnectOptions) {
        try {
            mMqttClient.connect(mqttConnectOptions, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.e(TAG, "xxx==连接成功");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.e(TAG, "xxx==连接失败:" + exception.getMessage());
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 订阅单个主题
     *
     * @param topic
     */
    public void subscribe(String topic) {
        if (mMqttClient == null) {
            Log.e(TAG, "xxx==subscribe==没有初始化MqttAndroidClient对象，订阅失败");
            return;
        }
        try {
            mMqttClient.subscribe(topic, 2, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.e(TAG, "xxx==subscribe==订阅某个主题成功");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    if (exception != null) {
                        Log.e(TAG, "xxx==subscribe==订阅订阅某个主题失败:" + exception.getMessage());
                    } else {
                        Log.e(TAG, "xxx==subscribe==订阅订阅某个主题失败:");
                    }
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 订阅多个主题
     *
     * @param topics
     */
    public void subscribe(String[] topics) {
        if (mMqttClient == null) {
            Log.e(TAG, "xxx==subscribe==没有初始化MqttAndroidClient对象，订阅失败");
            return;
        }
        int length = topics.length;
        final int[] qos = new int[length];
        for (int i = 0; i < length; i++)
            qos[i] = 2;
        try {
            mMqttClient.subscribe(topics, qos, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.e(TAG, "xxx==subscribe==批量订阅成功");
                    //订阅了主题之后发送上线通知
                    String imei = TelPhoneUtil.getIMEI(MessageService.this);
                    // ChatMessage message = new ChatMessage(chatmess.Type.SYSTEM, "OnlineNotice#&" + clientId + "_" + imei);
                    ChatMessage message = new ChatMessage(ChatMessageBody.Type.SYSTEM, clientId, clientId, System.currentTimeMillis());
                    ChatSysMessageBody chatSysMessageBody = new ChatSysMessageBody(ChatMessageBody.Type.SYSTEM);
                    chatSysMessageBody.action = ChatSysMessageBody.SysMessageType.ACTION_ONLINE_NOTICE;
                    chatSysMessageBody.content = chatSysMessageBody.action + ChatMessage.PREX + clientId + "_" + imei;
                    //message.message="OnlineNotice#&" + clientId + "_" + imei;
                    message.messageBody = chatSysMessageBody;
                    sendMessage("chat/" + clientId, message, null);
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.e(TAG, "xxx==subscribe==批量订阅失败:");
                    exception.printStackTrace();
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送消息
     */
    public void sendMessage(String topic, final ChatMessage chatMessage, final OnMessageSendListener listener) {
        RuntimeException re = new RuntimeException();
        re.fillInStackTrace();
        if (mMqttClient == null) {
            Log.e(TAG, "xxx==sendMessage==没有初始化MqttAndroidClient对象，发送消息失败");
            if (listener != null) {
                listener.sendFailure(chatMessage);
            }
            return;
        }
        if (!mMqttClient.isConnected()) {
            Log.e(TAG, "xxx==sendMessage==MqttAndroidClient没有连接上，发送消息失败");
            if (listener != null) {
                listener.sendFailure(chatMessage);
            }
            return;
        }
        Log.e("lwjing", "send message " + chatMessage.toString());
        final MqttMessage message = new MqttMessage();
        try {
            message.setPayload(SendPlayload.createData(chatMessage));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            Log.e(TAG, "xxx==sendMessage==编码失败，发送消息失败：" + e.getMessage());
        }
        try {
            mMqttClient.publish(topic, message, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    if (listener != null) {
                        listener.sendSuccess(chatMessage);
                    }
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    if (listener != null) {
                        listener.sendFailure(chatMessage);
                    }
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
            Log.e(TAG, "xxx==sendMessage==发送消息失败：" + e.getMessage());
        }
    }

    /**
     * 取消订阅某个主题
     *
     * @param topic
     */
    public void unSubscribe(String topic) {
        if (mMqttClient == null) {
            Log.e(TAG, "xxx==unSubscribe==没有初始化MqttAndroidClient对象，取消订阅失败");
            return;
        }
        try {
            mMqttClient.unsubscribe(topic, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.e(TAG, "xxx==unSubscribe==取消订阅成功");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.e(TAG, "xxx==unSubscribe==取消订阅失败");
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 断开mqtt连接
     */
    public void disConnect() {
        // java.lang.IllegalArgumentException - if the URI does not start with "tcp://", "ssl://" or "local://".
        // java.lang.IllegalArgumentException - if the clientId is null or is greater than 65535 characters in length
        if (mMqttClient == null) {
            Log.e(TAG, "xxx==disConnect==没有初始化MqttAndroidClient对象，取消连接失败");
            return;
        }

        try {
            if (!mMqttClient.isConnected()) {
                Log.e(TAG, "xxx==disConnect==未处于连接状态");
                return;
            }

            Log.e(TAG, "xxx==disConnect==断开连接");
            mConnectionLostListener = null;
            mMqttClient.disconnect();
            mMqttClient.unregisterResources();
            mMqttClient.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "xxx==disConnect==断开连接失败:" + e.getMessage());
        }
    }

    /**
     * 添加mqtt连接丢失的回调
     */
    public void registerConnectLostListener(ConnectionLostListener listener) {
        this.mConnectionLostListener = listener;
    }

    public void unregisterConnectionLostListener() {
        this.mConnectionLostListener = null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        disConnect();
        //disConnect();
        mMqttClient = null;
        EventBus.getDefault().unregister(this);
    }

    public interface ConnectionLostListener {
        void connectionLost();
    }
}

